freemd 0.1.1 → 0.1.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.es.md +5 -5
- package/README.md +3 -3
- package/bin/openmd.js +16 -16
- package/dist/assets/index-C0VJG4kI.css +1 -0
- package/dist/assets/index-D77myrtE.js +29 -0
- package/dist/index.html +3 -3
- package/package.json +1 -1
- package/server/export/to-docx.js +1 -1
- package/server/export/to-pdf.js +1 -1
- package/server/index.js +24 -24
- package/dist/assets/index-C0w_6LCS.css +0 -1
- package/dist/assets/index-CiAQinMf.js +0 -29
package/README.es.md
CHANGED
|
@@ -10,7 +10,7 @@ npx freemd
|
|
|
10
10
|
|
|
11
11
|
Eso es todo: crea `~/freemd` si no existe, levanta un servidor local en [http://localhost:5813](http://localhost:5813) y abre tu navegador.
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+

|
|
14
14
|
|
|
15
15
|
## Por qué freemd
|
|
16
16
|
|
|
@@ -73,12 +73,12 @@ Todo vive en una carpeta (por defecto `~/freemd`):
|
|
|
73
73
|
|
|
74
74
|
## La app
|
|
75
75
|
|
|
76
|
-
- **Sidebar** — tus notas y carpetas. Al pasar el cursor sobre un elemento aparecen renombrar (✏️) y eliminar (🗑); los iconos de la cabecera crean notas, carpetas y suben adjuntos a la nota actual.
|
|
77
|
-
- **Editor con tres modos** — *
|
|
76
|
+
- **Sidebar** — tus notas y carpetas. Al pasar el cursor sobre un elemento aparecen renombrar (✏️) y eliminar (🗑); los iconos de la cabecera crean notas, carpetas y suben adjuntos a la nota actual. Puedes plegarla con el botón de panel o `Cmd/Ctrl + B` (el estado se recuerda).
|
|
77
|
+
- **Editor con tres modos** — *Edit* (markdown crudo), *Split* (editor y vista renderizada lado a lado, con scroll sincronizado), *Preview* (solo preview). Los bloques de código llevan resaltado de sintaxis.
|
|
78
78
|
- **Panel de recursos** — panel plegable a la derecha con las imágenes de la nota actual en miniaturas. Haz click en una para insertar su markdown en el cursor; al pasar el cursor puedes eliminarla.
|
|
79
79
|
- **Pegar imágenes** — copia una captura o imagen y pulsa `Cmd/Ctrl + V` sobre la nota: se guarda en la carpeta de la nota y se inserta su markdown en el cursor.
|
|
80
|
-
- **
|
|
81
|
-
- **
|
|
80
|
+
- **Autosave** — los cambios se guardan solos 1.2 s después de dejar de escribir (o al instante con `Cmd/Ctrl + S`).
|
|
81
|
+
- **Export** — un click para descargar la nota como **PDF** o **Word (.docx)**: tema claro, código resaltado, imágenes incrustadas y con el nombre de la nota (`recetas.pdf`, nunca `index.pdf`). Si hay cambios sin guardar, se guardan primero.
|
|
82
82
|
|
|
83
83
|
## Desarrollo
|
|
84
84
|
|
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ npx freemd
|
|
|
10
10
|
|
|
11
11
|
That's it: it creates `~/freemd` if it doesn't exist, starts a local server at [http://localhost:5813](http://localhost:5813) and opens your browser.
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+

|
|
14
14
|
|
|
15
15
|
## Why freemd
|
|
16
16
|
|
|
@@ -73,8 +73,8 @@ Everything lives in one folder (by default `~/freemd`):
|
|
|
73
73
|
|
|
74
74
|
## The app
|
|
75
75
|
|
|
76
|
-
- **Sidebar** — your notes and folders. Hover any item to rename (✏️) or delete (🗑); the toolbar icons create notes, folders and upload attachments to the current note.
|
|
77
|
-
- **Editor with three view modes** — *
|
|
76
|
+
- **Sidebar** — your notes and folders. Hover any item to rename (✏️) or delete (🗑); the toolbar icons create notes, folders and upload attachments to the current note. Collapse it with the panel button or `Cmd/Ctrl + B` (state is remembered).
|
|
77
|
+
- **Editor with three view modes** — *Edit* (raw markdown), *Split* (editor and rendered preview side by side, scroll-synced), *Preview* (rendered only). Code blocks get syntax highlighting.
|
|
78
78
|
- **Resources panel** — a collapsible panel on the right showing the current note's images as thumbnails. Click one to insert its markdown at the cursor; hover to delete it.
|
|
79
79
|
- **Paste images** — copy a screenshot or image and press `Cmd/Ctrl + V` anywhere in the note: it's saved into the note's folder and its markdown inserted at the cursor.
|
|
80
80
|
- **Autosave** — changes save automatically 1.2 s after you stop typing (or instantly with `Cmd/Ctrl + S`).
|
package/bin/openmd.js
CHANGED
|
@@ -17,18 +17,18 @@ const valueOf = (...flags) => {
|
|
|
17
17
|
|
|
18
18
|
if (hasFlag('-h', '--help')) {
|
|
19
19
|
console.log(`
|
|
20
|
-
freemd —
|
|
20
|
+
freemd — markdown notes editor in your browser
|
|
21
21
|
|
|
22
|
-
|
|
23
|
-
npx freemd [
|
|
22
|
+
Usage:
|
|
23
|
+
npx freemd [options]
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
-p, --port <n>
|
|
27
|
-
-d, --dir <
|
|
28
|
-
-H, --host <addr>
|
|
29
|
-
--no-open
|
|
30
|
-
-v, --version
|
|
31
|
-
-h, --help
|
|
25
|
+
Options:
|
|
26
|
+
-p, --port <n> Server port (default 5813)
|
|
27
|
+
-d, --dir <path> Notes folder (default ~/freemd)
|
|
28
|
+
-H, --host <addr> Listen on another interface; no value binds 0.0.0.0 (whole local network)
|
|
29
|
+
--no-open Do not open the browser automatically
|
|
30
|
+
-v, --version Print version
|
|
31
|
+
-h, --help Show this help
|
|
32
32
|
`);
|
|
33
33
|
process.exit(0);
|
|
34
34
|
}
|
|
@@ -45,7 +45,7 @@ if (portArg === undefined) {
|
|
|
45
45
|
} else {
|
|
46
46
|
port = Number(portArg);
|
|
47
47
|
if (!Number.isInteger(port) || port < 1 || port > 65535) {
|
|
48
|
-
console.error(`
|
|
48
|
+
console.error(`Invalid port: ${portArg}`);
|
|
49
49
|
process.exit(1);
|
|
50
50
|
}
|
|
51
51
|
}
|
|
@@ -63,18 +63,18 @@ try {
|
|
|
63
63
|
const { url, root, migrated } = await start({ port, dir, host, open });
|
|
64
64
|
console.log('');
|
|
65
65
|
console.log(` freemd ${pkg.version}`);
|
|
66
|
-
console.log(`
|
|
67
|
-
if (migrated) console.log(`
|
|
68
|
-
console.log(`
|
|
66
|
+
console.log(` notes ${root}`);
|
|
67
|
+
if (migrated) console.log(` migrated ${migrated} → ${root}`);
|
|
68
|
+
console.log(` ready ${url}`);
|
|
69
69
|
if (host === '0.0.0.0' || host === '::') {
|
|
70
70
|
for (const address of lanAddresses(port)) {
|
|
71
|
-
console.log(`
|
|
71
|
+
console.log(` network ${address}`);
|
|
72
72
|
}
|
|
73
73
|
}
|
|
74
74
|
console.log('');
|
|
75
75
|
} catch (error) {
|
|
76
76
|
if (error.code === 'EADDRINUSE') {
|
|
77
|
-
console.error(`
|
|
77
|
+
console.error(`Port ${port} is already in use. Try --port <another port>`);
|
|
78
78
|
} else {
|
|
79
79
|
console.error(error.message ?? error);
|
|
80
80
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
pre code.hljs{display:block;overflow-x:auto;padding:1em}code.hljs{padding:3px 5px}.hljs{color:#abb2bf;background:#282c34}.hljs-comment,.hljs-quote{color:#5c6370;font-style:italic}.hljs-doctag,.hljs-keyword,.hljs-formula{color:#c678dd}.hljs-section,.hljs-name,.hljs-selector-tag,.hljs-deletion,.hljs-subst{color:#e06c75}.hljs-literal{color:#56b6c2}.hljs-string,.hljs-regexp,.hljs-addition,.hljs-attribute,.hljs-meta .hljs-string{color:#98c379}.hljs-attr,.hljs-variable,.hljs-template-variable,.hljs-type,.hljs-selector-class,.hljs-selector-attr,.hljs-selector-pseudo,.hljs-number{color:#d19a66}.hljs-symbol,.hljs-bullet,.hljs-link,.hljs-meta,.hljs-selector-id,.hljs-title{color:#61aeee}.hljs-built_in,.hljs-title.class_,.hljs-class .hljs-title{color:#e6c07b}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}.hljs-link{text-decoration:underline}:root{--bg: #282c34;--bg-darker: #21252b;--bg-darkest: #1b1e24;--bg-panel: #2c313a;--bg-hover: #333842;--border: #3a3f4b;--border-dark: #181a1f;--fg: #abb2bf;--fg-bright: #d7dae0;--fg-dim: #5c6370;--red: #e06c75;--orange: #d19a66;--yellow: #e5c07b;--green: #98c379;--cyan: #56b6c2;--blue: #61afef;--purple: #c678dd;--mono: ui-monospace, "SF Mono", "Cascadia Code", Menlo, Consolas, "Liberation Mono", monospace}*{box-sizing:border-box}html,body,#app{height:100%;margin:0}body{background:var(--bg);color:var(--fg);font-family:Inter,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif;font-size:14px;-webkit-font-smoothing:antialiased}::selection{background:#61afef47}::-webkit-scrollbar{width:10px;height:10px}::-webkit-scrollbar-track{background:transparent}::-webkit-scrollbar-thumb{background:var(--border);border-radius:5px;border:2px solid transparent;background-clip:content-box}::-webkit-scrollbar-thumb:hover{background:var(--fg-dim);border:2px solid transparent;background-clip:content-box}button{font-family:inherit}.app{display:flex;height:100%;overflow:hidden}.main{flex:1;display:flex;flex-direction:column;min-width:0;position:relative}.sidebar-slot{width:280px;min-width:280px;flex-shrink:0;overflow:hidden;transition:width .18s ease,min-width .18s ease}.sidebar-slot.collapsed{width:0;min-width:0}.sidebar{width:280px;min-width:280px;height:100%;display:flex;flex-direction:column;background:var(--bg-darker);border-right:1px solid var(--border-dark)}.side-head{display:flex;align-items:center;justify-content:space-between;height:48px;padding:0 10px 0 16px;border-bottom:1px solid var(--border-dark);flex-shrink:0}.brand{font-size:15px;font-weight:600;letter-spacing:.4px;color:var(--fg-bright)}.brand-md{color:var(--green)}.head-actions{display:flex;gap:2px}.icon-btn{display:inline-flex;align-items:center;justify-content:center;width:30px;height:30px;padding:0;border:none;border-radius:6px;background:none;color:var(--fg-dim);cursor:pointer}.icon-btn:hover:not(:disabled){color:var(--fg-bright);background:var(--bg-panel)}.icon-btn:disabled{opacity:.35;cursor:default}.new-item{padding:10px;border-bottom:1px solid var(--border-dark)}.new-item input{width:100%;padding:7px 10px;font-size:13px;color:var(--fg-bright);background:var(--bg-darkest);border:1px solid var(--blue);border-radius:6px;outline:none}.new-item input::placeholder{color:var(--fg-dim)}.tree{flex:1;overflow-y:auto;padding:8px 6px}.tree-loading,.tree-empty{padding:16px 12px;font-size:12.5px;line-height:1.6;color:var(--fg-dim)}.item{display:flex;align-items:center;border-radius:6px}.item .row{flex:1;display:flex;align-items:center;gap:7px;min-width:0;padding:5px 8px;border:none;border-radius:6px;background:none;color:var(--fg);font-size:13px;text-align:left;cursor:pointer}.item .row:hover{background:var(--bg-panel)}.item.active .row{background:var(--bg-panel);color:var(--fg-bright)}.item .label{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.chev{display:inline-flex;align-items:center;justify-content:center;width:11px;flex-shrink:0;color:var(--fg-dim)}.chev svg{transition:transform .15s ease}.chev.open svg{transform:rotate(90deg)}.icon{display:inline-flex;flex-shrink:0}.t-note{color:var(--purple)}.t-folder{color:var(--blue)}.t-md{color:var(--cyan)}.t-image{color:var(--orange)}.t-file{color:var(--fg-dim)}.item .del{display:inline-flex;align-items:center;justify-content:center;width:26px;height:26px;margin-right:4px;padding:0;border:none;border-radius:6px;background:none;color:var(--fg-dim);cursor:pointer;visibility:hidden;flex-shrink:0}.rename-item{padding:2px 6px 2px 0}.rename-item input{width:100%;padding:4px 8px;font-size:13px;color:var(--fg-bright);background:var(--bg-darkest);border:1px solid var(--blue);border-radius:6px;outline:none}.item:hover .del{visibility:visible}.item .del:hover{color:var(--red);background:var(--bg-panel)}.side-foot{display:flex;flex-direction:column;gap:8px;padding:12px;border-top:1px solid var(--border-dark);flex-shrink:0}.upload-btn{display:flex;align-items:center;justify-content:center;gap:8px;padding:8px;font-size:12.5px;color:var(--fg);background:var(--bg-panel);border:1px solid var(--border);border-radius:8px;cursor:pointer}.upload-btn:hover:not(:disabled){color:var(--blue);border-color:var(--blue)}.upload-btn:disabled{opacity:.4;cursor:default}.root-hint{font-size:11px;font-family:var(--mono);color:var(--fg-dim);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.toolbar{display:flex;align-items:center;gap:12px;height:48px;padding:0 16px;background:var(--bg-darker);border-bottom:1px solid var(--border-dark);flex-shrink:0}.meta{display:flex;align-items:center;gap:9px;min-width:0}.meta .name{font-size:13px;font-weight:500;color:var(--fg-bright);white-space:nowrap}.meta .crumb{font-size:12px;color:var(--fg-dim);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.unsaved{width:7px;height:7px;border-radius:50%;background:var(--yellow);flex-shrink:0}.spacer{flex:1}.count{font-size:12px;color:var(--fg-dim);white-space:nowrap}.seg{display:flex;padding:2px;background:var(--bg-darkest);border:1px solid var(--border);border-radius:8px}.seg button{padding:5px 12px;font-size:12px;border:none;border-radius:6px;background:transparent;color:var(--fg-dim);cursor:pointer}.seg button.active{background:var(--bg-panel);color:var(--fg-bright)}.save-btn{display:flex;align-items:center;gap:7px;padding:6px 12px;font-size:12.5px;color:var(--blue);background:var(--bg-panel);border:1px solid var(--border);border-radius:8px;cursor:pointer}.save-btn:hover:not(:disabled){border-color:var(--blue)}.save-btn:disabled{color:var(--fg-dim);opacity:.6;cursor:default}.export-wrap{position:relative}.export-chev{display:inline-flex;color:var(--fg-dim)}.export-chev svg{transition:transform .15s ease}.export-chev.open svg{transform:rotate(180deg)}.menu-backdrop{position:fixed;top:0;right:0;bottom:0;left:0;z-index:44;padding:0;border:none;background:transparent;cursor:default}.export-menu{position:absolute;top:calc(100% + 6px);right:0;z-index:45;display:flex;flex-direction:column;min-width:150px;padding:4px;background:var(--bg-darker);border:1px solid var(--border);border-radius:8px;box-shadow:0 10px 32px #00000073}.export-menu button{display:flex;align-items:center;gap:8px;padding:8px 10px;border:none;border-radius:6px;background:none;color:var(--fg);font-size:12.5px;text-align:left;cursor:pointer}.export-menu button:hover{background:var(--bg-panel);color:var(--fg-bright)}.editor-body{flex:1;display:flex;min-height:0}.autosaved{font-size:11.5px;color:var(--green);white-space:nowrap}.panel-btn.active{color:var(--blue);background:var(--bg-panel)}.resources{width:240px;flex-shrink:0;display:flex;flex-direction:column;background:var(--bg-darker);border-left:1px solid var(--border-dark);overflow:hidden}.res-head{display:flex;align-items:center;justify-content:space-between;height:40px;padding:0 6px 0 14px;font-size:11px;font-weight:600;letter-spacing:.8px;text-transform:uppercase;color:var(--fg-dim);border-bottom:1px solid var(--border-dark);flex-shrink:0}.res-actions{display:flex;gap:2px}.res-empty{padding:14px;font-size:12px;line-height:1.6;color:var(--fg-dim)}.res-scroll{flex:1;overflow-y:auto}.res-grid{display:grid;grid-template-columns:repeat(2,1fr);gap:8px;padding:10px}.res-item{position:relative;aspect-ratio:1;padding:0;border:1px solid var(--border);border-radius:6px;background:var(--bg-panel);overflow:hidden;cursor:pointer}.res-item:hover{border-color:var(--blue)}.res-remove{position:absolute;top:4px;right:4px;display:flex;align-items:center;justify-content:center;width:18px;height:18px;padding:0;border:none;border-radius:4px;background:#181a1fd9;color:var(--red);cursor:pointer;opacity:0}.res-item:hover .res-remove,.res-remove:focus-visible{opacity:1}.res-remove:hover{background:var(--bg-darkest)}.res-item img{display:block;width:100%;height:100%;object-fit:cover}.res-file{display:flex;align-items:center;justify-content:center;height:100%;color:var(--fg-dim)}.res-name{position:absolute;left:4px;right:4px;bottom:4px;padding:2px 6px;font-size:10px;text-align:left;color:#fff;background:#181a1fcc;border-radius:4px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}textarea.code{flex:1;width:100%;padding:24px 32px;border:none;outline:none;resize:none;background:var(--bg);color:var(--fg);font-family:var(--mono);font-size:14px;line-height:1.75;caret-color:var(--blue)}textarea.code.half{flex:1 1 50%;width:auto;min-width:0;padding:20px 24px;border-right:1px solid var(--border-dark)}.preview-wrap.half{flex:1 1 50%;min-width:0}.preview-wrap.half .preview{padding:24px 24px 60px}.preview-wrap{flex:1;overflow-y:auto}.preview{max-width:760px;margin:0 auto;padding:36px 48px 80px;font-size:15px;line-height:1.75}.preview h1,.preview h2,.preview h3,.preview h4{color:var(--fg-bright);line-height:1.3;margin:1.6em 0 .6em}.preview h1,.preview h2{padding-bottom:.3em;border-bottom:1px solid var(--border)}.preview h1{margin-top:.4em}.preview p{margin:.8em 0}.preview a{color:var(--blue);text-decoration:none}.preview a:hover{text-decoration:underline}.preview code{padding:2px 6px;border-radius:4px;background:#3a3f4b;color:var(--yellow);font-family:var(--mono);font-size:.88em}.preview pre{padding:16px;overflow-x:auto;background:var(--bg-darker);border:1px solid var(--border);border-radius:8px;line-height:1.6}.preview pre code{padding:0;background:none;color:inherit;font-size:13px}.preview blockquote{margin:1em 0;padding:2px 16px;color:var(--fg-dim);border-left:3px solid var(--fg-dim)}.preview ul,.preview ol{padding-left:1.6em}.preview li{margin:.3em 0}.preview img{max-width:100%;border-radius:6px}.preview hr{margin:1.6em 0;border:none;border-top:1px solid var(--border)}.preview table{border-collapse:collapse;margin:1em 0;width:100%}.preview th,.preview td{padding:7px 12px;border:1px solid var(--border)}.preview th{background:var(--bg-panel);color:var(--fg-bright)}.media-view{flex:1;display:flex;align-items:center;justify-content:center;overflow:auto;padding:32px}.media-view img{max-width:100%;max-height:100%;border-radius:8px;box-shadow:0 8px 40px #0006}.empty{flex:1;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:10px;color:var(--fg-dim);position:relative}.sidebar-open{position:absolute;top:9px;left:10px}.primary-btn{display:flex;align-items:center;gap:8px;margin-top:8px;padding:9px 18px;font-size:13px;font-weight:600;color:var(--bg-darkest);background:var(--green);border:none;border-radius:8px;cursor:pointer}.primary-btn:hover{filter:brightness(1.1)}.logo{margin:0;font-size:30px;font-weight:600;letter-spacing:1px;color:#3e4451}.toast{position:fixed;bottom:24px;left:50%;transform:translate(-50%);padding:10px 16px;font-size:13px;color:var(--fg-bright);background:var(--bg-darkest);border:1px solid var(--border);border-radius:8px;box-shadow:0 8px 30px #00000059;z-index:100;animation:rise .2s ease}.toast.error{color:var(--red);border-color:var(--red)}@keyframes rise{0%{opacity:0;transform:translate(-50%) translateY(8px)}to{opacity:1;transform:translate(-50%) translateY(0)}}
|